import java.awt.Color;
import java.awt.Graphics2D;
import java.util.ArrayList;

import org.jbox2d.collision.AABB;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.joints.DistanceJoint;
import org.jbox2d.dynamics.joints.MouseJoint;
import org.jbox2d.dynamics.joints.RevoluteJoint;

import pulpcore.CoreSystem;
import pulpcore.Stage;
import pulpcore.image.BlendMode;
import pulpcore.image.CoreFont;
import pulpcore.image.CoreGraphics;
import pulpcore.Input;
import pulpcore.scene.Scene2D;
import pulpcore.sound.Sound;
import pulpcore.sprite.Group;
import pulpcore.sprite.ImageSprite;
import pulpcore.sprite.Label;
import pulpcore.sprite.Sprite;
import pulpfizz.physics.Actor;
import pulpfizz.physics.BodyUtils;
import pulpfizz.physics.JointUtils;
import pulpfizz.physics.Material;
import pulpfizz.physics.NewWorld;
import pulpfizz.physics.PhysicsTileMap;
import pulpfizz.pulp.CameraControlledScene;
import pulpfizz.pulp.CameraSprite;
import pulpfizz.pulp.body.BodySprite;
import pulpfizz.pulp.body.ImageBodySprite;
import pulpfizz.pulp.body.Java2DBodySprite;
import pulpfizz.pulp.body.PhysicsLayer;
import pulpfizz.pulp.body.SimpleBodyDrawer;
import pulpfizz.pulp.ui.LabelBox;
import pulpfizz.pulp.ui.SmoothMouse;

public class HelloWorld extends CameraControlledScene
{
	private SmoothMouse sm;
	private MouseJoint mj;
	private PhysicsLayer physics;
    private Label sprite;
    private BodySprite boxSprite;
    private BodySprite bodySprite;
    private ArrayList<BodySprite> creatures = new ArrayList<BodySprite>();
    private ArrayList<BodySprite> boxes = new ArrayList<BodySprite>();
    
    private ArrayList<Actor> actorUpdateRegistry = new ArrayList<Actor>();

    LabelBox hudSprite;
    
    MadSnake[] mySnakes;
    
    @Override
	public void load()
	{
        super.load();
        Stage.setFrameRate(60);

		//camera.setRespondToInput(false);

		/*
		 * Create a Physics sprite, with objects display at 50x their size.
		 */
		physics = new PhysicsLayer(20);

        physics.setAnchor(Sprite.CENTER);
		add(physics);
		physics.fitToStage();
//		physics.width.set(physics.width.get()*4);
//		physics.height.set(physics.height.get()*4);

        physics.setGravity(new Vec2(0,-10.0f));
        
        sm = new SmoothMouse();
		add(sm);
		setCursor(Input.CURSOR_HAND);
		
		hudSprite = new LabelBox("",0,0);
		addToHUD(hudSprite);
        
        createWorld();
	}
    
	public void createWorld()
	{
        PhysicsTileMap tileMap = PhysicsTileMap.createSimpleTileMap();
        tileMap.bindImageFromFile('#', "square.png");
        tileMap.bindImageFromFile('O', "circle.png");
        tileMap.bindImageFromFile('/', "frontslash.png");
        tileMap.bindImageFromFile('|', "backslash.png");
        tileMap.bindImageFromFile('t', "bg.png");
        
        String[] mapString = {
        	"###################",
        	"##   B   ##### ####",
        	"##   /######## ####",
        	"## t           ####",
        	"##          /######",
        	"## O           ####",
        	"##   /      #######",
        	"## O   |tttt   ####",
        	"##   /|tt/tt#######",
        	"###################"
        };
        
        AABB aabb = tileMap.setAABBFromMap(mapString, -30.0f, -20.0f, 4.0f, 4.0f);
        
        float physWidth = 300f*Math.max(Math.abs(aabb.lowerBound.x), Math.abs(aabb.upperBound.x));
        float physHeight = 300f*Math.max(Math.abs(aabb.lowerBound.y), Math.abs(aabb.upperBound.y));
        
        physics.setPhysicsDimensions(physWidth, physHeight);

		NewWorld world = physics.getWorld();

        ArrayList<BodySprite> sprites = tileMap.createTileMap(mapString, mapString, aabb, world, physics);
        System.out.println(sprites.size()+" sprites created.");
        
        mySnakes = new MadSnake[50];
		for (int i=0; i<mySnakes.length; ++i) {
			mySnakes[i] = new MadSnake(new Vec2(0.0f,5.0f-.3f*i), new Vec2(1.0f,5.0f-.3f*i-1.0f), 7, physics);
		}
        
        //camera.followBody(physics, mySnakes[0].head, 0.5);
        //camera.setMoveDuration(200);
        camera.zoomBy(0.4);
        
        boxSprite = mySnakes[0].sprites.get(0);
	}
	
	int timeElapsed = 0, numFrames=0;
	   
    @Override
	public void update(int elapsedTime)
	{
		super.update(elapsedTime);
		//physics.update(elapsedTime);
		// FPS counter
        timeElapsed += elapsedTime;
        numFrames++;
        if(timeElapsed >= 1000) {
            timeElapsed = 0;
            hudSprite.setText("FPS="+ numFrames);
            numFrames=0;
        }
        
        for (int i=0; i<mySnakes.length; ++i) {
        	mySnakes[i].update(elapsedTime);
        }
        
        if (Input.isMousePressed() && physics != null) {
			double pX = physics.getPhysicsX(
				sm.x.get(), sm.y.get());
			double pY = physics.getPhysicsY(
				sm.x.get(), sm.y.get());
			Vec2 p = new Vec2( (float)pX, (float)pY );
			Body[] bList = BodyUtils.getAllBodiesInCircle(physics.getWorld(), p, 2.0f);
			if (bList != null) {
				for (int i=0; i<bList.length; ++i) {
					Body b = bList[i];
					Vec2 imp = p.sub(b.getWorldCenter());
					imp.normalize();
					imp.mulLocal(-0.5f);
					b.applyImpulse(imp, b.getWorldCenter());
				}
			}
		}
        
        if (Input.isDown(Input.KEY_D)) {
        	boxSprite.getBody().applyForce(new Vec2(2.0f,0.0f), boxSprite.getBody().getWorldCenter());
        }
        if (Input.isDown(Input.KEY_A)) {
        	boxSprite.getBody().applyForce(new Vec2(-2.0f,0.0f), boxSprite.getBody().getWorldCenter());
        }
        if (Input.isDown(Input.KEY_W)) {
        	boxSprite.getBody().applyForce(new Vec2(0.0f,2.0f), boxSprite.getBody().getWorldCenter());
        }
        if (Input.isDown(Input.KEY_S)) {
        	boxSprite.getBody().applyForce(new Vec2(0.0f,-2.0f), boxSprite.getBody().getWorldCenter());
        }
        if (Input.isDown(Input.KEY_Q)) {
        	boxSprite.getBody().applyTorque(2.0f);
        }
        if (Input.isDown(Input.KEY_E)) {
        	boxSprite.getBody().applyTorque(-2.0f);
        }
	}

	@Override
	public synchronized void add(Sprite sprite)
	{
		super.add(sprite);
	}

}